# Package pour les expressions régulières
import re
# Package de manipaulation des tableaux et dataframe
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, cross_val_score, RandomizedSearchCV
from sklearn.feature_selection import VarianceThreshold, RFECV, SelectKBest, chi2, mutual_info_classif
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, RobustScaler
from sklearn.pipeline import Pipeline, make_pipeline
from sklearn.compose import make_column_transformer
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, BaggingClassifier
from sklearn.metrics import roc_auc_score,confusion_matrix,f1_score,classification_report,PrecisionRecallDisplay,precision_recall_curve,average_precision_score,precision_recall_fscore_support
from sklearn.calibration import calibration_curve, CalibratedClassifierCV
from imblearn.over_sampling import RandomOverSampler
from itertools import cycle
import pickle
# Boruta pour sélection de variables
from boruta import BorutaPy
# Package xgboost
from xgboost import XGBClassifier
# Package pour analyse statistique
import scipy.stats as ss
from scipy.stats import chi2_contingency
# Package pour représentation graphique
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import plotly.graph_objects as go
import scikitplot as skplt
# Affichage Image (png, jpeg, html ...)
from IPython.display import Image, HTML
# Typing des fonctions
from typing import List, Optional
from functools import reduce
from sklearn.inspection import permutation_importance, PartialDependenceDisplay
import shap
from lime import lime_tabular
C:\Users\user\.conda\envs\SDA_P4\lib\site-packages\tqdm\auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html from .autonotebook import tqdm as notebook_tqdm
# ---------------------------------------Fonction-------------------
# Création d'une dataframe de distribution
def distrib_calc(var1,var2,var3):
df_temp = pd.DataFrame(var1.value_counts(normalize=True) * 100).reset_index().rename(columns={"index": var2, var3: "count"})
return df_temp
# Représentation graphique : bar plot target
def distrib_graph(var1,var2,var3):
fig = px.bar(var1,
y="count", x="target",
hover_data={'count':':.2f'}
)
fig.update_layout(
title=var2,
xaxis_title="Pourcentage par parti politique",
yaxis_title=var3,
margin=dict(l=0, r=0, t=30, b=50),
width=500, height=300
)
return fig.show()
# Représentation graphique pour varibales numériques
def repres_graph(var_y,var_x,var_analyse):
fig, ax = plt.subplots(1, 2, figsize=(8, 6))
sns.boxplot(x=var_y, y=var_x, ax=ax[0], palette=["#011C5D", "#D38F00"])
ax[0].set_xlabel(var_analyse)
sns.violinplot(x=var_y, y=var_x, ax=ax[1], palette=["#011C5D", "#D38F00"])
ax[1].set_xlabel(var_analyse)
return
# Représentation graphique d'un tableau de contingence
def table_cont_graph(var_index,var_col,name_col,var_sort):
df_crosstab = (pd.crosstab(index=var_index,
columns=var_col,
normalize="index")
.sort_values(var_sort)
)
sns.set(style='white')
#create stacked bar chart
df_crosstab.plot(kind='bar', stacked=True, color=['steelblue', 'red'])
#add overall title
plt.title(name_col, fontsize=16)
#add axis titles
plt.xlabel('Partie Politique')
plt.ylabel(name_col)
#rotate x-axis labels
plt.xticks(rotation=45)
def corr_matrice(df_anal):
person_matrix = df_anal.corr()
# Filtrer sur le matrice triangulaire inférieure (ou supérieure)
mask = np.triu(np.ones_like(person_matrix))
# Visualisation de la matrice de corrélation
fig, ax = plt.subplots(figsize=(15, 13))
sns.heatmap(person_matrix, vmin=-1, vmax=1, mask=mask, annot=True, ax=ax) #
def detect_corr(corr, seuil):
""" Représente les variables ayant une corrélation en valeur absolue > seuil
----------
Paramètres
corr: matrice de corrélation
seuil: valeur numérique représentant le niveau de corrélation que l'on considère comme étant une limite
----------
Output
corr_table: DataFrame des variables corrélées et valeur de corrélation en valeur absolue
"""
tmp = []
for i in range(len(corr.columns.values)):
A = corr.loc[:, corr.columns.values[i]]
for j in range(i):
if (abs(A[j]) >= seuil) and (A.index[j] != corr.columns.values[i]):
tmp.append((corr.columns.values[i], A.index[j], A[j]))
corr_table = pd.DataFrame(tmp, columns=["Variable_1", "Variable_2", "Corr_Seuil_Valeur_Absolue"])
return corr_table
def detect_corr_to_keep(corr, seuil):
""" Représente les variables ayant une corrélation en valeur absolue < seuil
----------
Paramètres
corr: matrice de corrélation
seuil: valeur numérique représentant le niveau de corrélation que l'on considère comme étant une limite
----------
Output
corr_table: DataFrame des variables corrélées et valeur de corrélation en valeur absolue
"""
tmp = []
for i in range(len(corr.columns.values)):
A = corr.loc[:, corr.columns.values[i]]
for j in range(i):
if (abs(A[j]) <= seuil) and (A.index[j] != corr.columns.values[i]):
tmp.append((corr.columns.values[i], A.index[j], A[j]))
corr_table = pd.DataFrame(tmp, columns=["Variable_1", "Variable_2", "Corr_Seuil_Valeur_Absolue"])
return corr_table
# calcul V de Cramer pour deux variables
def cramer_v_coeff(x: List, y: List) -> float:
"""Cette fonction permet de calculer le V de
Cramer entre deux varaibles catégorielles.
Args:
x : Le vecteur de variable x.
y : Le vecteur de variable y.
Returns:
float: La valeur V de cramer.
"""
# Virer les NAs
complete_cases = x.isna()*y.isna()
x = x[~complete_cases]
y = y[~complete_cases]
# Calcul du Khi-deux max (dénomimateur du V de Cramer)
n = len(x)
chi2_max = n * min(len(x.value_counts()), len(y.value_counts())) - 1
# Calcul du khi-deux (numérateur du V de Cramer)
cross_tabs = pd.crosstab(x, y)
chi2, p, dof, con_table = ss.chi2_contingency(cross_tabs)
#print(f'chi-squared = {chi2}\np value= {p}\ndegrees of freedom = {dof}')
#khi2 = chi2_contingency(observed=conf_matrix, correction=True)
# Calcul V de Cramer et récupération p_value associée
cramer = round(np.sqrt(chi2 / chi2_max), 4)
p_value = p
dof = dof
return cramer, p_value, dof
# calcul V de Cramer pour un dataframe
# Laisser les étudiants boucler eux mêmes
def compute_cramer_v(data: pd.DataFrame) -> pd.DataFrame:
"""Calculer le V de cramer pour un dataframe.
Args:
data: Jeu de données sur lequel on souhaite
calculer le V de Cramer.
Returns:
DataFrame contenant les différents V de Cramer.
"""
ncols = data.shape[1]
cols = data.columns
cramer_matrix = np.eye(ncols)
for j in range(ncols - 1):
for i in range(j + 1, ncols):
cramer_matrix[[i, j], [j, i]] = cramer_v_coeff(
x=data.iloc[:, j],
y=data.iloc[:, i]
)[0]
cramer_matrix = pd.DataFrame(cramer_matrix, columns=cols, index=cols)
return cramer_matrix
def del_top_lines(nb,df_init):
# Fonction qui supprime :
# - les première lignes d'un tableau,
# - renomme les colonnes
# - crée un nouvel index en préservant l'ancien
#
#
# nb : index number of the new head table to keep
# df_init : dataframe to change
print(".......index new head number : ", nb)
df_fin_trans = df_init.iloc[nb:]
df_fin_trans.columns = df_fin_trans.values[0]
df_fin_trans = df_fin_trans.iloc[1:].reset_index().rename(columns={"index": "old_index"})
return df_fin_trans
# Fonction de de récupération des variables de base, i.e sans dummies
def get_features_names(dummies_features):
features_filter = []
for col in dummies_features:
# Définir l'expression régulière pour récupération de la racine de la variable col
search_col = re.search(f"(.+)___", col)
# Renvoyer la racine si c'est une variable encodée, sinon la variable col.
if search_col:
features_filter.append(search_col.group(1))
else:
features_filter.append(col)
return np.unique(features_filter).tolist()
# définition de fonction pour fitter les modèles
def fit_model(X, y, estimator, **kwargs):
# séparer les colonnes en numérique et catégorielles
num_cols = X.select_dtypes(include=np.number).columns
cat_cols = X.select_dtypes(exclude=np.number).columns
# Preprocessing des variables : imputation, encodage et normalisation
# Traitement des variables numériques
num_pipeline = make_pipeline(
SimpleImputer(strategy='median'),
RobustScaler()
)
# Traitement des variables ccatégorielles
cat_pipeline = make_pipeline(
SimpleImputer(strategy='constant', fill_value='missing'),
OneHotEncoder(handle_unknown='ignore')
)
# Combinaison des deux pipelines
preprocessor = make_column_transformer(
(num_pipeline, num_cols),
(cat_pipeline, cat_cols)
)
model = Pipeline(
steps=[
("preprocessor", preprocessor),
("estimator", estimator)
]
)
return model.fit(X_train, y_train, **kwargs)
# Évaluation du modèle
def model_evaluation(model, X_train, y_train, X_test, y_test):
# Prédiction sur le jeu de données test
y_train_pred = model.predict_proba(X_train)
#print("y_train : ", y_train)
#print("y_train_pred : ", y_train_pred)
y_test_pred = model.predict_proba(X_test)
#print("y_test : ", y_test)
#print("y_test_pred : ", y_test_pred)
# ---------------------- Calcul de l'AUC----------------------------------------
auc_train = roc_auc_score(y_train, y_train_pred[:,1])
auc_test = roc_auc_score(y_test, y_test_pred[:,1])
# ---------------------- Calcul Matrice de confusion----------------------------
# Définition d'un seuil de classification (par exemple 60%)
threshold = 0.5
# Labels prédits pour un seuil donné
y_train_pred_threshold = (y_train_pred[:,1] > threshold).astype(int)
#print("y_train_pred_threshold : ", y_train_pred_threshold)
y_test_pred_threshold = (y_test_pred[:,1] > threshold).astype(int)
#print("y_test_pred_threshold : ", y_test_pred_threshold)
# Calcul de la matrice de confusion pour un seuil donné
matrix_threshold_train = confusion_matrix(y_true=y_train, y_pred=y_train_pred_threshold)
matrix_threshold_test = confusion_matrix(y_true=y_test, y_pred=y_test_pred_threshold)
# ---------------------- Calcul F1 SCORE----------------------------------------
f1_score_train = f1_score(y_true=y_train, y_pred=y_train_pred_threshold, average=None)
f1_score_test = f1_score(y_true=y_test, y_pred=y_test_pred_threshold, average=None)
class_report_f1_train = classification_report(y_true=y_train, y_pred=y_train_pred_threshold, labels=[0,1])
class_report_f1_test = classification_report(y_true=y_test, y_pred=y_test_pred_threshold, labels=[0,1])
return auc_train, auc_test , matrix_threshold_train, matrix_threshold_test, f1_score_train, f1_score_test,class_report_f1_train,class_report_f1_test
def display_model_evaluation(X_train, y_train, X_test, y_test, select_model, model_name, step, init_model): #Step 0 : test simple de modelisation, Step 1 : Modif paramètre, Step 2 : Calibrage
if step == 0 :
print("------------------------------------------------------- PHASE DE MODELISATION SIMPLE ---------------------------------------------------")
if step == 1 :
print("------------------------------------------ PHASE D'OPTIMISATION DES HYPERPARAMETRES -----------------------------------------------------")
fit_m = fit_model(X_train, y_train, select_model)
evaluation = model_evaluation(fit_m, X_train, y_train, X_test, y_test)
df_mat_conf_train = pd.DataFrame(evaluation[2])
df_mat_conf_train.rename(index = {0: 'Réelle Positif', 1: 'Réelle négatif'},columns = {0: 'Prédiction positive', 1: 'Prédiction négative'}, inplace = True)
df_mat_conf_test = pd.DataFrame(evaluation[3])
df_mat_conf_test.rename(index = {0: 'Réelle Positif', 1: 'Réelle négatif'},columns = {0: 'Prédiction positive', 1: 'Prédiction négative'}, inplace = True)
y_pred_test = fit_m.predict_proba(X_test)[:, 1]
spiegel_test = score_spiegelhalter(y_test, y_pred_test)
print("\n------------- Métrique d'évaluation AUC ------------- ")
print("\n Score AUC sur TRAIN : ", round(evaluation[0], 4),
"\n Score AUC sur TEST : ", round(evaluation[1], 4)
)
print("\n------------- Matrice de confusion ------------- ")
print("\nMatrice de Confusion sur y TRAIN: \n ", df_mat_conf_train,
"\nMatrice de Confusion sur y TEST: \n ", df_mat_conf_test
)
print("\n------------- Métrique d'évaluation F1 SCORE ------------- ")
print("\n F1 Score sur y TRAIN : ", evaluation[4],
"\n F1 Score sur y TEST : ", evaluation[5]
)
print("\n------------- Classification Report : F1 SCORE ------------- ")
print("\n Classification report sur TRAIN : \n", evaluation[6],
"\n Classification report sur TEST : \n", evaluation[7]
)
print("\n------------- Score de Spiegelhalter ------------- ")
print("\n Score sur TEST : \n", spiegel_test)
print("\n--------------------Courbe de Lift ------------------\n")
lift_sk_curve(X_test, y_test, fit_m)
print("\n--------------------Courbe Precision / Recall------------------\n")
precision_recall_curve(X_test, y_test, fit_m, 1)
print("\n--------------------Courbe de calibrage------------------\n")
calibration_curve_display(X_test, y_test, fit_m)
if step >= 1:
print("\n-------------------- Export du modèle au format .sav avec optimisation des hyperparamètres------------------\n")
filename = model_name + '_bef_cal.sav'
pickle.dump(fit_m, open(filename, 'wb'))
print("....Fichier ", filename," exporté")
if step >= 2 :
print("-------------------------------------------- PHASE DE CALIBRAGE FINALE -----------------------------------------------------")
# Récupérez les paramètres du modèle chargé
parameters = (fit_m
.named_steps
.estimator
.best_params_
)
fit_m_cal = init_model
# Définissez les paramètres de cet estimateur.
fit_m_cal.set_params(**parameters)
# Instancier le modèle de calibration
calibrated_cv_clf = CalibratedClassifierCV(
base_estimator=fit_m_cal,
method="sigmoid", #isotonic risque d'overfit si <1000
cv=5,
n_jobs=-1
)
fit_m = fit_model(X_train, y_train, calibrated_cv_clf)
evaluation = model_evaluation(fit_m, X_train, y_train, X_test, y_test)
df_mat_conf_train = pd.DataFrame(evaluation[2])
df_mat_conf_train.rename(index = {0: 'Réelle Positif', 1: 'Réelle négatif'},columns = {0: 'Prédiction positive', 1: 'Prédiction négative'}, inplace = True)
df_mat_conf_test = pd.DataFrame(evaluation[3])
df_mat_conf_test.rename(index = {0: 'Réelle Positif', 1: 'Réelle négatif'},columns = {0: 'Prédiction positive', 1: 'Prédiction négative'}, inplace = True)
y_pred_test = fit_m.predict_proba(X_test)[:, 1]
spiegel_test = score_spiegelhalter(y_test, y_pred_test)
print("\n---------------------------- PARAMETRES OPTIMAUX UTILISES PAR LE MODELE : -------------------------------- \n")
print(parameters)
print("\n------------- Métrique d'évaluation AUC ------------- ")
print("\n Score AUC sur TRAIN : ", round(evaluation[0], 4),
"\n Score AUC sur TEST : ", round(evaluation[1], 4)
)
print("\n------------- Matrice de confusion ------------- ")
print("\nMatrice de Confusion sur y TRAIN: \n ", df_mat_conf_train,
"\nMatrice de Confusion sur y TEST: \n ", df_mat_conf_test
)
print("\n------------- Métrique d'évaluation F1 SCORE ------------- ")
print("\n F1 Score sur y TRAIN : ", evaluation[4],
"\n F1 Score sur y TEST : ", evaluation[5]
)
print("\n------------- Classification Report : F1 SCORE ------------- ")
print("\n Classification report sur TRAIN : \n", evaluation[6],
"\n Classification report sur TEST : \n", evaluation[7]
)
print("\n------------- Score de Spiegelhalter ------------- ")
print("\n Score sur TEST : \n", spiegel_test)
print("\n--------------------Courbe de Lift ------------------\n")
lift_sk_curve(X_test, y_test, fit_m)
print("\n--------------------Courbe Precision / Recall------------------\n")
precision_recall_curve(X_test, y_test, fit_m, 1)
print("\n--------------------Courbe de calibrage------------------\n")
calibration_curve_display(X_test, y_test, fit_m)
if step == 2:
print("\n-------------------- Export du modèle au format .sav après calibrage------------------\n")
filename = model_name + '_cal.sav'
pickle.dump(fit_m, open(filename, 'wb'))
print(".... Fichier ", filename," exporté")
return
def lift_sk_curve(X_test, y_test, model):
# Courbe de lift avec scikitplot
plt.figure(figsize=(8,8))
skplt.metrics.plot_cumulative_gain(
y_true=y_test,
y_probas=model.predict_proba(X_test)
)
plt.show()
return
def precision_recall_curve(X_test, y_test, model, classif):
# Courbe de Precision Recall
y_pred = model.predict_proba(X_test)[:, int(classif)]
PrecisionRecallDisplay.from_predictions(y_test, y_pred)
plt.show()
return
def score_spiegelhalter(y_true, y_pred):
numerateur = np.sum(np.multiply(y_true - y_pred, 1 - 2 * y_pred))
denominateur = np.sqrt(
np.sum(
np.multiply(
np.multiply(np.power(1 - 2 * y_pred, 2), y_pred), 1 - y_pred
)
)
)
score = abs(numerateur / denominateur)
return score
def calibration_curve_display(X_test, y_test, model):
# Prédiction sur le jeu de données test
y_pred = model.predict_proba(X_test)[:, 1]
# Construction de la table de données
sklearn_calibration_df = sklearn_calibration(y_test, y_pred)
# Représentation graphique
xlim_ylim_sklearn = sklearn_calibration_df.values.max()
fig = px.scatter(
sklearn_calibration_df,
x="prob_pred",
y="prob_true"
)
fig.add_trace(
go.Scatter(
x=[0, xlim_ylim_sklearn],
y=[0, xlim_ylim_sklearn],
mode="lines",
line=go.scatter.Line(color="gray"),
showlegend=False)
)
fig.update_layout(
xaxis_title="Moyenne des probabilités",
yaxis_title="Proportion des positifs (y = 1)",
yaxis=dict(scaleanchor="x", scaleratio=1),
xaxis=dict(constrain='domain'),
margin=dict(l=0, r=0, t=30, b=50),
width=600, height=400
)
fig.show()
return
def sklearn_calibration(y_true, y_pred):
prob_true, prob_pred = calibration_curve(y_true, y_pred, n_bins=10, strategy="quantile")
df = pd.DataFrame({"prob_pred":prob_pred, "prob_true":prob_true})
return df
# Dictionnaire des états
dict_states = {"United States" : "US", "Alabama" : "AL", "Alaska" : "AK", "Arizona" : "AZ", "Arkansas" : "AR", "California" : "CA", "Colorado" : "CO", "Connecticut" : "CT", "Delaware" : "DE", "District of Columbia" : "DC", "Florida" : "FL", "Georgia" : "GA", "Hawaii" : "HI", "Idaho" : "ID", "Illinois" : "IL", "Indiana" : "IN", "Iowa" : "IA", "Kansas" : "KS", "Kentucky" : "KY", "Louisiana" : "LA", "Maine" : "ME", "Maryland" : "MD", "Massachusetts" : "MA", "Michigan" : "MI", "Minnesota" : "MN", "Mississippi" : "MS", "Missouri" : "MO", "Montana" : "MT", "Nebraska" : "NE", "Nevada" : "NV", "New Hampshire" : "NH", "New Jersey" : "NJ", "New Mexico" : "NM", "New York" : "NY", "North Carolina" : "NC", "North Dakota" : "ND", "Ohio" : "OH", "Oklahoma" : "OK", "Oregon" : "OR", "Pennsylvania" : "PA", "Rhode Island" : "RI", "South Carolina" : "SC", "South Dakota" : "SD", "Tennessee" : "TN", "Texas" : "TX", "Utah" : "UT", "Vermont" : "VT", "Virginia" : "VA", "Washington" : "WA", "West Virginia" : "WV", "Wisconsin" : "WI", "Wyoming" : "WY"}
#---------------------------------------IMPORT DES DONNEES----------------------------------------------------------
print(".IMPORT DES DONNEES")
# On spécifie le chemin d'accès aux données
folder_path = "./data/"
# On importe les fichiers
print(".... Import des fichiers excels et CSV")
df_pres_result = pd.read_csv(folder_path + "2020_US_County_Level_Presidential_Results.csv", sep = ",")
df_pres_result_old = pd.read_csv(folder_path + "US_County_Level_Presidential_Results_08-16.csv", sep = ",")
df_education = pd.read_excel(folder_path + "Education.xls")
df_pop_est = pd.read_excel(folder_path + "PopulationEstimates.xls")
df_pov_est = pd.read_excel(folder_path + "PovertyEstimates.xls")
df_unemp = pd.read_excel(folder_path + "Unemployment.xls")
#-------------------------------------------- REGROUPEMENT DES DONNES SOCIOECONOMIQUES -----------------------
print(".REGROUPEMENT DES DONNES SOCIOECONOMIQUES")
# Mise en forme et Modification des entêtes des fichiers excels
print(".... Mise en forme et Modification des entêtes des fichiers excels")
df_education = del_top_lines(3,df_education)
df_pop_est = del_top_lines(1,df_pop_est)
df_pov_est = del_top_lines(3,df_pov_est)
df_unemp = del_top_lines(3,df_unemp)
# Uniformisation du code FIPS du fichier CSV
print(".... Uniformisation du code FIPS")
df_pres_result['county_fips'] = df_pres_result['county_fips'].astype(str)
df_pres_result['county_fips'] = df_pres_result['county_fips'].apply(lambda x: '0' + x if len(x) == 4 else x)
#print(df_pres_result['county_fips'])
update_name_col_1 = 'FIPS_code'
update_name_col_2 = 'State_code'
update_name_col_3 = 'Area_name'
update_name_col_4 = 'Rural_urban_continuum_code_2013'
update_name_col_5 = 'Urban_influence_code_2013'
update_name_col_6 = 'State_name'
# Uniformisation des noms de colonnes communes à chaque fichier
print(".... Uniformisation des noms de colonnes communes à chaque fichier")
df_pres_result.rename(columns={'county_fips': update_name_col_1, 'state_name': update_name_col_6, 'county_name' : update_name_col_3}, inplace=True)
df_education.rename(columns={'FIPS Code': update_name_col_1, 'State': update_name_col_2, 'Area name' : update_name_col_3, '2013 Rural-urban Continuum Code' : update_name_col_4, '2013 Urban Influence Code' : update_name_col_5}, inplace=True)
df_pop_est.rename(columns={'FIPStxt': update_name_col_1, 'State': update_name_col_2, 'Area_Name' : update_name_col_3, 'Rural-urban_Continuum Code_2013' : update_name_col_4, 'Urban_Influence_Code_2013' : update_name_col_5}, inplace=True)
df_pov_est.rename(columns={'FIPStxt': update_name_col_1, 'Stabr': update_name_col_2, 'Area_name' : update_name_col_3, 'Rural-urban_Continuum_Code_2013' : update_name_col_4, 'Urban_Influence_Code_2013' : update_name_col_5}, inplace=True)
df_unemp.rename(columns={'fips_txt': update_name_col_1, 'Stabr': update_name_col_2, 'area_name' : update_name_col_3, 'Rural_urban_continuum_code_2013' : update_name_col_4, 'Urban_influence_code_2013' : update_name_col_5}, inplace=True)
# Création d'une nouvelle colonne
print(".... Création d'une nouvelle colonne : ", update_name_col_2)
df_pres_result[update_name_col_2] = df_pres_result[update_name_col_6]
df_pres_result[update_name_col_2]=df_pres_result[update_name_col_2].replace(dict_states)
# Ajout de nouvelles lignes (niveau ETATS) dans la DF des résultats de 2020 afin de garder une cohérence avec les autrs fichiers
# Supprimer le 16/11 car présence de ligne vide trop impactante pour l'analyse
#print(".... Ajout du niveau 'état' dans le fichier cible")
#df_states = pd.DataFrame({update_name_col_1 : ["00000", "01000", "02000", "04000", "05000", "06000", "08000", "09000", "10000", "11000", "12000", "13000", "15000", "16000", "17000", "18000", "19000", "20000", "21000", "22000", "23000", "24000", "25000", "26000", "27000", "28000", "29000", "30000", "31000", "32000", "33000", "34000", "35000", "36000", "37000", "38000", "39000", "40000", "41000", "42000", "44000", "45000", "46000", "47000", "48000", "49000", "50000", "51000", "53000", "54000", "55000", "56000"],
# update_name_col_2 : ["US", "AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY"],
# update_name_col_3 : ["United States", "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "District of Columbia", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Lousiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"],
# update_name_col_6 : ["United States", "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "District of Columbia", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Lousiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"]})
#df_pres_result = pd.concat([df_pres_result, df_states])
# Selection du périmètre du premier périmètre d'analyse
# Attention : code FIPS, State, area, rural et urban influance déjà uniforme
print(".... Selection du périmètre du premier périmètre d'analyse")
col_educ_perim = [update_name_col_1,
#update_name_col_2,
#update_name_col_3,
update_name_col_4,
update_name_col_5,
#"Less than a high school diploma, 2015-19",
#"High school diploma only, 2015-19",# On ne garde que 2 colonnes : Less than high school et bachelor of higher
#"Some college or associate's degree, 2015-19",# On ne garde que 2 colonnes : Less than high school et bachelor of higher
#"Bachelor's degree or higher, 2015-19"]
"Percent of adults with less than a high school diploma, 2015-19",# On ne garde que 2 colonnes : Less than high school et bachelor of higher
"Percent of adults with a high school diploma only, 2015-19",# On ne garde que 2 colonnes : Less than high school et bachelor of higher
"Percent of adults completing some college or associate's degree, 2015-19",# On ne garde que 2 colonnes : Less than high school et bachelor of higher
"Percent of adults with a bachelor's degree or higher, 2015-19"]# On ne garde que 2 colonnes : Less than high school et bachelor of higher
col_pop_est_perim = [update_name_col_1,
#update_name_col_2,
#update_name_col_3,
#update_name_col_4,
#update_name_col_5,
#"Economic_typology_2015",
#"POP_ESTIMATE_2015",
#"POP_ESTIMATE_2016",
#"POP_ESTIMATE_2017",
#"POP_ESTIMATE_2018",
"POP_ESTIMATE_2019",
#"N_POP_CHG_2015",
#"N_POP_CHG_2016",
#"N_POP_CHG_2017",
#"N_POP_CHG_2018",
"N_POP_CHG_2019",
#"Births_2015",
#"Births_2016",
#"Births_2017",
#"Births_2018",
#"Births_2019",# Information récupéré dans NATURAL INC
#"Deaths_2015",
#"Deaths_2016",
#"Deaths_2017",
#"Deaths_2018",
#"Deaths_2019", # Information récupéré dans NATURAL INC
#"NATURAL_INC_2015",
#"NATURAL_INC_2016",
#"NATURAL_INC_2017",
#"NATURAL_INC_2018",
#"NATURAL_INC_2019", #
#"INTERNATIONAL_MIG_2015",
#"INTERNATIONAL_MIG_2016",
#"INTERNATIONAL_MIG_2017",
#"INTERNATIONAL_MIG_2018",
#"INTERNATIONAL_MIG_2019",
#"DOMESTIC_MIG_2015",
#"DOMESTIC_MIG_2016",
#"DOMESTIC_MIG_2017",
#"DOMESTIC_MIG_2018",
#"DOMESTIC_MIG_2019",
#"NET_MIG_2015",
#"NET_MIG_2016",
#"NET_MIG_2017",
#"NET_MIG_2018",
"NET_MIG_2019",
#"RESIDUAL_2015",
#"RESIDUAL_2016",
#"RESIDUAL_2017",
#"RESIDUAL_2018",
#"RESIDUAL_2019",
#"GQ_ESTIMATES_2015",
#"GQ_ESTIMATES_2016",
#"GQ_ESTIMATES_2017",
#"GQ_ESTIMATES_2018",
#"GQ_ESTIMATES_2019",
#"R_birth_2015", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_birth_2016", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_birth_2017", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_birth_2018", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_birth_2019", # supprimé car trop de corrélation avec les autres variables
#"R_death_2015", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_death_2016", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_death_2017", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_death_2018", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_death_2019",# supprimé car trop de corrélation avec les autres variables
#"R_NATURAL_INC_2015", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_NATURAL_INC_2016", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_NATURAL_INC_2017", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_NATURAL_INC_2018", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
"R_NATURAL_INC_2019",# supprimé car trop de corrélation avec les autres variables
#"R_INTERNATIONAL_MIG_2015", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_INTERNATIONAL_MIG_2016", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_INTERNATIONAL_MIG_2017", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_INTERNATIONAL_MIG_2018", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
"R_INTERNATIONAL_MIG_2019",# supprimé car trop de corrélation avec les autres variables
#"R_DOMESTIC_MIG_2015", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_DOMESTIC_MIG_2016", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_DOMESTIC_MIG_2017", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_DOMESTIC_MIG_2018", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
"R_DOMESTIC_MIG_2019"]# supprimé car trop de corrélation avec les autres variables
#"R_NET_MIG_2015", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_NET_MIG_2016", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_NET_MIG_2017", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_NET_MIG_2018", #R entre 2015 et 2018 supprimé car trop de corrélation entre n et n-1.
#"R_NET_MIG_2019"]# supprimé car trop de corrélation avec les autres variables
col_pov_est_perim = [update_name_col_1,
#update_name_col_2,
#update_name_col_3,
#update_name_col_4,
#update_name_col_5,
#"POVALL_2019", # trp corrélé à POP ESTIMATE et PCTPOVALL ci-dessous déjà inclu
"PCTPOVALL_2019"]
#"POV017_2019", #supprimé car ces gens ne votent pas
#"PCTPOV017_2019", #supprimé car ces gens ne votent pas
#"POV517_2019", #supprimé car ces gens ne votent pas
#"PCTPOV517_2019"] #supprimé car ces gens ne votent pas
#"MEDHHINC_2019"] déjà présent dans le fichier sur unemployment
#"POV04_2019"] Supprimer car contient trop de NAn pour l'analyse des données
#"PCTPOV04_2019"] Supprimer car contient trop de NAn pour l'analyse des données
col_unemp_perim = [update_name_col_1,
#update_name_col_2,
#update_name_col_3,
#update_name_col_4,
#update_name_col_5,
"Metro_2013",
#"Civilian_labor_force_2015",
#"Employed_2015",
#"Unemployed_2015",
#"Unemployment_rate_2015", #Taux avant 2019 supprimer car trop de corrélation avec 2019
#"Civilian_labor_force_2016",
#"Employed_2016",
#"Unemployed_2016",
#"Unemployment_rate_2016", #Taux avant 2019 supprimer car trop de corrélation avec 2019
#"Civilian_labor_force_2017",
#"Employed_2017",
#"Unemployed_2017",
#"Unemployment_rate_2017", #Taux avant 2019 supprimer car trop de corrélation avec 2019
#"Civilian_labor_force_2018",
#"Employed_2018",
#"Unemployed_2018",
#"Unemployment_rate_2018", #Taux avant 2019 supprimer car trop de corrélation avec 2019
#"Employed_2019", # trop corrélé à la variable Unemployment_rate_2019 ci-après
#"Unemployed_2019", # trop corrélé à la variable Unemployment_rate_2019 ci-après
"Unemployment_rate_2019",
"Median_Household_Income_2019"]
#"Med_HH_Income_Percent_of_State_Total_2019"
print(".... Réduction du scope : selection du périmètre du premier périmètre d'analyse des fichiers excels")
df_education = df_education[col_educ_perim]
df_pop_est = df_pop_est[col_pop_est_perim]
df_pov_est = df_pov_est[col_pov_est_perim]
df_unemp = df_unemp[col_unemp_perim]
# création d'une liste des dataframe à traiter
print(".... Création d'une liste des dataframe à traiter")
df_list = [df_pres_result,df_education,df_pop_est,df_pov_est,df_unemp]
# Info et affichage premières lignes
#print(".... Info et affichage premières lignes")
#for d in df_list:
#print(d.info())
#display(d.head())
# Jointure en boucle sur toutes les DF sur l'élément update_name_col_1
print(".... Jointure en boucle sur toutes les DF sur l'élément : ", update_name_col_1)
df_merged = pd.DataFrame()
df_merged = reduce(lambda left,right: pd.merge(left,right,on=[update_name_col_1],how='inner'), df_list)
# Conversion de données
list_object = ['State_name', 'FIPS_code','Area_name','State_code', 'Rural_urban_continuum_code_2013','Urban_influence_code_2013','Metro_2013','Economic_typology_2015']
print(".... Conversion de toutes les données au format numérique sauf : ", list_object)
list_all_col = list(df_merged.columns)
for col in list_all_col :
if col not in list_object:
df_merged[col] = df_merged[col].astype(float)
# Création de la variable cible Party:
print(".... Création de la variable cible Party:")
df_merged['Party'] = np.where(df_merged['per_gop']>=df_merged['per_dem'], 1, 0)
# Feature Engineering
#df_merged['R_INT_DOM_MIG_2019'] = df_merged['INTERNATIONAL_MIG_2019'] / df_merged['DOMESTIC_MIG_2019']
#df_merged['R_INT_DOM_MIG_2019'] = df_merged['R_INT_DOM_MIG_2019'].fillna(0)
#df_merged.drop(['INTERNATIONAL_MIG_2019'], axis=1, inplace = True)
#df_merged.drop(['DOMESTIC_MIG_2019'], axis=1, inplace = True)
# Suppression des lignes Nan du subset Party
print(".... Suppression des lignes Nan du subset Party:")
df_merged = df_merged.dropna(subset=['Party'])
# Update de l'indexation
print(".... Update de l'indexation:")
df_merged = df_merged.reset_index(drop=True)
# Suppression des features (En effet, ces données sont les résultats direct de l'élection)
print(".... Suppression des features correspond aux résultats de l'election:")
df_merged = df_merged.drop(['votes_gop', 'votes_dem', 'total_votes', 'diff', 'per_gop', 'per_dem','per_point_diff'], axis=1)
df_merged.set_index("FIPS_code", inplace = True)
print(df_merged.info(verbose=True, show_counts=True))
print(df_merged.describe())
display(df_merged.head())
.IMPORT DES DONNEES
.... Import des fichiers excels et CSV
.REGROUPEMENT DES DONNES SOCIOECONOMIQUES
.... Mise en forme et Modification des entêtes des fichiers excels
.......index new head number : 3
.......index new head number : 1
.......index new head number : 3
.......index new head number : 3
.... Uniformisation du code FIPS
.... Uniformisation des noms de colonnes communes à chaque fichier
.... Création d'une nouvelle colonne : State_code
.... Selection du périmètre du premier périmètre d'analyse
.... Réduction du scope : selection du périmètre du premier périmètre d'analyse des fichiers excels
.... Création d'une liste des dataframe à traiter
.... Jointure en boucle sur toutes les DF sur l'élément : FIPS_code
.... Conversion de toutes les données au format numérique sauf : ['State_name', 'FIPS_code', 'Area_name', 'State_code', 'Rural_urban_continuum_code_2013', 'Urban_influence_code_2013', 'Metro_2013', 'Economic_typology_2015']
.... Création de la variable cible Party:
.... Suppression des lignes Nan du subset Party:
.... Update de l'indexation:
.... Suppression des features correspond aux résultats de l'election:
<class 'pandas.core.frame.DataFrame'>
Index: 3112 entries, 01001 to 56045
Data columns (total 20 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 State_name 3112 non-null object
1 Area_name 3112 non-null object
2 State_code 3112 non-null object
3 Rural_urban_continuum_code_2013 3112 non-null object
4 Urban_influence_code_2013 3112 non-null object
5 Percent of adults with less than a high school diploma, 2015-19 3112 non-null float64
6 Percent of adults with a high school diploma only, 2015-19 3112 non-null float64
7 Percent of adults completing some college or associate's degree, 2015-19 3112 non-null float64
8 Percent of adults with a bachelor's degree or higher, 2015-19 3112 non-null float64
9 POP_ESTIMATE_2019 3112 non-null float64
10 N_POP_CHG_2019 3112 non-null float64
11 NET_MIG_2019 3112 non-null float64
12 R_NATURAL_INC_2019 3112 non-null float64
13 R_INTERNATIONAL_MIG_2019 3112 non-null float64
14 R_DOMESTIC_MIG_2019 3112 non-null float64
15 PCTPOVALL_2019 3112 non-null float64
16 Metro_2013 3112 non-null object
17 Unemployment_rate_2019 3112 non-null float64
18 Median_Household_Income_2019 3112 non-null float64
19 Party 3112 non-null int32
dtypes: float64(13), int32(1), object(6)
memory usage: 498.4+ KB
None
Percent of adults with less than a high school diploma, 2015-19 \
count 3112.000000
mean 13.085088
std 6.265950
min 1.116910
25% 8.479882
50% 11.739182
75% 16.708521
max 73.560211
Percent of adults with a high school diploma only, 2015-19 \
count 3112.000000
mean 34.147758
std 7.226061
min 7.265136
25% 29.689806
50% 34.538523
75% 39.099957
max 57.433674
Percent of adults completing some college or associate's degree, 2015-19 \
count 3112.000000
mean 30.802965
std 5.211923
min 5.235602
25% 27.290243
50% 30.785382
75% 34.214836
max 60.563381
Percent of adults with a bachelor's degree or higher, 2015-19 \
count 3112.000000
mean 21.964189
std 9.582236
min 0.000000
25% 15.325250
50% 19.557242
75% 25.989834
max 77.557411
POP_ESTIMATE_2019 N_POP_CHG_2019 NET_MIG_2019 R_NATURAL_INC_2019 \
count 3.112000e+03 3112.000000 3112.000000 3112.000000
mean 1.052403e+05 499.876607 194.142352 0.535900
std 3.349233e+05 2978.156191 2932.456367 3.904831
min 1.690000e+02 -34799.000000 -79758.000000 -13.540491
25% 1.113550e+04 -97.000000 -110.000000 -1.980223
50% 2.616300e+04 6.000000 -1.000000 0.288647
75% 6.857625e+04 239.000000 179.000000 2.698155
max 1.003911e+07 83011.000000 62997.000000 24.429062
R_INTERNATIONAL_MIG_2019 R_DOMESTIC_MIG_2019 PCTPOVALL_2019 \
count 3112.000000 3112.000000 3112.000000
mean 0.627073 -0.255445 14.470662
std 1.405652 12.420941 5.793896
min -1.735609 -165.250965 2.700000
25% 0.000000 -5.951671 10.400000
50% 0.214936 -0.717189 13.400000
75% 0.760167 5.446392 17.500000
max 26.041667 126.182965 47.700000
Unemployment_rate_2019 Median_Household_Income_2019 Party
count 3112.000000 3112.000000 3112.000000
mean 3.960925 55602.652956 0.827121
std 1.390290 14451.719339 0.378204
min 0.700000 24732.000000 0.000000
25% 3.000000 46181.000000 1.000000
50% 3.700000 53257.000000 1.000000
75% 4.600000 61810.750000 1.000000
max 18.300000 151806.000000 1.000000
| State_name | Area_name | State_code | Rural_urban_continuum_code_2013 | Urban_influence_code_2013 | Percent of adults with less than a high school diploma, 2015-19 | Percent of adults with a high school diploma only, 2015-19 | Percent of adults completing some college or associate's degree, 2015-19 | Percent of adults with a bachelor's degree or higher, 2015-19 | POP_ESTIMATE_2019 | N_POP_CHG_2019 | NET_MIG_2019 | R_NATURAL_INC_2019 | R_INTERNATIONAL_MIG_2019 | R_DOMESTIC_MIG_2019 | PCTPOVALL_2019 | Metro_2013 | Unemployment_rate_2019 | Median_Household_Income_2019 | Party | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| FIPS_code | ||||||||||||||||||||
| 01001 | Alabama | Autauga County | AL | 2 | 2 | 11.483395 | 33.588459 | 28.356571 | 26.571573 | 55869.0 | 336.0 | 254.0 | 1.490099 | -0.287248 | 4.847310 | 12.1 | 1 | 2.7 | 58233.0 | 1 |
| 01003 | Alabama | Baldwin County | AL | 3 | 2 | 9.193843 | 27.659616 | 31.284081 | 31.862459 | 223234.0 | 5379.0 | 5377.0 | -0.099753 | 0.362739 | 24.017829 | 10.1 | 1 | 2.7 | 59871.0 | 1 |
| 01005 | Alabama | Barbour County | AL | 6 | 6 | 26.786907 | 35.604542 | 26.029837 | 11.578713 | 24686.0 | -186.0 | -128.0 | -2.259978 | 0.524638 | -5.690302 | 27.1 | 0 | 3.8 | 35972.0 | 1 |
| 01007 | Alabama | Bibb County | AL | 1 | 1 | 20.942602 | 44.878773 | 23.800098 | 10.378526 | 22394.0 | 27.0 | 41.0 | -0.536181 | 0.446818 | 1.385134 | 20.3 | 1 | 3.1 | 47918.0 | 1 |
| 01009 | Alabama | Blount County | AL | 1 | 1 | 19.509438 | 33.422131 | 33.975021 | 13.093413 | 57826.0 | 55.0 | 65.0 | -0.103809 | 0.103809 | 1.020788 | 16.3 | 1 | 2.7 | 52902.0 | 1 |
#-------------------------------------------- PREPARATION DU JEU DE DONNEES POUR ANALYSE -----------------------
print(".PREPARATION DU JEU DE DONNEES POUR ANALYSE")
# Séparer les variables explicatives de la target
print(".... Séparation des variables explicatives de la target Party")
# define oversampling strategy
oversample = RandomOverSampler(sampling_strategy='minority')
X_init = df_merged.drop(["Party"], axis=1)
y_init = df_merged["Party"]
# fit and apply the transform
X, y = oversample.fit_resample(X_init, y_init)
# split des données en train et test
print(".... Split des données en train et test")
set_seed = 42
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=set_seed)
# Création de listes selon typologie pour la phase exploratoire (numeric ou object)
print(".... Création de listes selon typologie pour la phase exploratoire (numeric ou object):")
cat_cols = X_train.select_dtypes(exclude=np.number).columns.tolist()
num_cols = X_train.select_dtypes(include=np.number).columns.tolist()
all_cols = X_train.columns.tolist()
# ------------------------------------DISTRIBUTION DE LA feature target 'party'-----------------------------------------------
print(".... Distribution de la feature target 'Party':")
target_distribution_bef_split = distrib_calc(y_init,"target","Party")
distrib_graph(target_distribution_bef_split,"Repartition de la target sur le jeu initial","Target (GOP/DEM)")
target_distribution = distrib_calc(y_train,"target","Party")
distrib_graph(target_distribution,"Repartition de la target sur le jeu y train","Target (GOP/DEM)")
# Représentation graphique pour varibales numériques
for col in num_cols:
repres_graph(y_train,X_train[col],"Target")
# Représentation graphique pour varibales catégorielles
for col in cat_cols:
if col not in {'FIPS_code','Area_name'}:
table_cont_graph(X_train[col],y_train,col,1)
.PREPARATION DU JEU DE DONNEES POUR ANALYSE .... Séparation des variables explicatives de la target Party .... Split des données en train et test .... Création de listes selon typologie pour la phase exploratoire (numeric ou object): .... Distribution de la feature target 'Party':
# Calcul et visualisation de la matrice de corrélation
corr_matrice(X_train[num_cols])
seuil = 0.8
base_corr = detect_corr(X_train[num_cols].corr(), seuil)
base_corr.to_csv('./export_base_corr.csv', index = True, header=True)
print(".... Corrélation entre 2 variables supérieur au seuil de : ", seuil)
display(base_corr)
#display(base_corr.values)
print(".... Corrélation entre 2 variables inférieur au seuil de : ", seuil)
base_corr_to_keep = detect_corr_to_keep(X_train[num_cols].corr(), seuil)
display(base_corr_to_keep)
.... Corrélation entre 2 variables supérieur au seuil de : 0.8
| Variable_1 | Variable_2 | Corr_Seuil_Valeur_Absolue | |
|---|---|---|---|
| 0 | Percent of adults with a bachelor's degree or ... | Percent of adults with a high school diploma o... | -0.838918 |
| 1 | NET_MIG_2019 | N_POP_CHG_2019 | 0.846337 |
.... Corrélation entre 2 variables inférieur au seuil de : 0.8
| Variable_1 | Variable_2 | Corr_Seuil_Valeur_Absolue | |
|---|---|---|---|
| 0 | Percent of adults with a high school diploma o... | Percent of adults with less than a high school... | 0.330077 |
| 1 | Percent of adults completing some college or a... | Percent of adults with less than a high school... | -0.304446 |
| 2 | Percent of adults completing some college or a... | Percent of adults with a high school diploma o... | 0.019354 |
| 3 | Percent of adults with a bachelor's degree or ... | Percent of adults with less than a high school... | -0.622940 |
| 4 | Percent of adults with a bachelor's degree or ... | Percent of adults completing some college or a... | -0.275300 |
| ... | ... | ... | ... |
| 71 | Median_Household_Income_2019 | R_NATURAL_INC_2019 | 0.378168 |
| 72 | Median_Household_Income_2019 | R_INTERNATIONAL_MIG_2019 | 0.250375 |
| 73 | Median_Household_Income_2019 | R_DOMESTIC_MIG_2019 | 0.218909 |
| 74 | Median_Household_Income_2019 | PCTPOVALL_2019 | -0.768259 |
| 75 | Median_Household_Income_2019 | Unemployment_rate_2019 | -0.475028 |
76 rows × 3 columns
pearson_matrix = []
print(".... Calcul des coefficient de pearson entre les variables et la target")
for col in num_cols:
person_values = ss.pearsonr(
x=X_train[col],
y=y_train
)
pearson_matrix.append(
{
'features': col,
'pearson_coeff': round(person_values[0], 4),
'pearson_coeff_abs': round(abs(person_values[0]), 4),
'p_value': round(person_values[1], 4)
}
)
pearson_matrix = (pd.DataFrame(pearson_matrix)
.sort_values(["pearson_coeff_abs"])
.reset_index(drop=True)
)
display(pearson_matrix)
print(".... Représentation graphique et decrochage de la courbe")
fig = px.bar(
pearson_matrix,
x="pearson_coeff_abs",
y="features",
hover_data=['p_value'],
orientation='h',
text="pearson_coeff"
)
fig.add_hrect(y0="duration",
y1="cons.price.idx",
annotation_text="Décrochage de la courbe",
annotation_position="bottom right",
line_color="#D38F00", line_dash="dash",
line_width=1
)
fig.show()
.... Calcul des coefficient de pearson entre les variables et la target
| features | pearson_coeff | pearson_coeff_abs | p_value | |
|---|---|---|---|---|
| 0 | NET_MIG_2019 | 0.0521 | 0.0521 | 0.0082 |
| 1 | Percent of adults with less than a high school... | 0.0528 | 0.0528 | 0.0074 |
| 2 | N_POP_CHG_2019 | -0.0980 | 0.0980 | 0.0000 |
| 3 | Unemployment_rate_2019 | -0.1024 | 0.1024 | 0.0000 |
| 4 | PCTPOVALL_2019 | -0.1349 | 0.1349 | 0.0000 |
| 5 | R_DOMESTIC_MIG_2019 | 0.1529 | 0.1529 | 0.0000 |
| 6 | Median_Household_Income_2019 | -0.2064 | 0.2064 | 0.0000 |
| 7 | R_NATURAL_INC_2019 | -0.2338 | 0.2338 | 0.0000 |
| 8 | Percent of adults completing some college or a... | 0.2588 | 0.2588 | 0.0000 |
| 9 | R_INTERNATIONAL_MIG_2019 | -0.2958 | 0.2958 | 0.0000 |
| 10 | POP_ESTIMATE_2019 | -0.3126 | 0.3126 | 0.0000 |
| 11 | Percent of adults with a bachelor's degree or ... | -0.4715 | 0.4715 | 0.0000 |
| 12 | Percent of adults with a high school diploma o... | 0.5094 | 0.5094 | 0.0000 |
.... Représentation graphique et decrochage de la courbe
# Construction dataframe contenant à la fois les coefficients
# du V de Cramer et la p-value associée à chaque variable catégorielle
print(".... analyse de liaison entre les variables catégorielles")
cramer_matrix = []
for col in cat_cols:
if col not in {'FIPS_code','Area_name'}: # ces variables sont retirés car non essentiels pour le modèle
# Calculer le V de Cramer entre la variable col et y
cramer_values = cramer_v_coeff(x=X_train[col], y=y_train)
# Concatener dans le dictionnaire contenant la variable col,
# la valeur du V de Cramer et la p-value de significativité
cramer_matrix.append(
{
'features': col,
'cramer_v': cramer_values[0],
'p_value': round(cramer_values[1], 4),
'DoF': cramer_values[2]
}
)
# Transformer la liste de dictionnaires en dataframe
# pour faciliter les manipulations à venir
cramer_matrix = (pd.DataFrame(cramer_matrix)
.sort_values(["cramer_v"])
.reset_index(drop=True)
)
print(cramer_matrix)
# Représentation graphique
fig = px.bar(
cramer_matrix,
x='cramer_v',
y='features',
hover_data=['p_value'],
title="Représentation des variables les plus corrélés à la variable cible",
orientation='h'
)
# Encadrer le top 5 des variables les plus liées à la cible
fig.add_hrect(y0=cramer_matrix['features'].iloc[-1],
y1=cramer_matrix['features'].iloc[-5],
annotation_text="Top 5 des variables",
annotation_position="bottom right",
line_color="#D38F00", line_dash="dash",
line_width=1
)
fig.show()
fig = px.bar(
cramer_matrix,
x='cramer_v',
y='features',
hover_data=['p_value'],
title="Représentation des variables filtrer par p value",
orientation='h',
text="p_value"
)
fig.add_hrect(y0=cramer_matrix[cramer_matrix['p_value']<0.05]['features'].iloc[-1],
y1=cramer_matrix[cramer_matrix['p_value']<0.05]['features'].iloc[0],
annotation_text="variables avec p-value < 0.05",
annotation_position="bottom right",
line_color="#D38F00", line_dash="dash",
line_width=1
)
fig.show()
# Fixer une valeur référence de liaison (ex. : 0,1)
fig = px.bar(
cramer_matrix,
x='cramer_v',
y='features',
hover_data=['p_value'],
title="Représentation des variables filtrer avec un seuil de liaison minimale",
orientation='h',
text="cramer_v"
)
fig.add_hrect(y0=cramer_matrix[cramer_matrix['cramer_v']>0.1]['features'].iloc[-1],
y1=cramer_matrix[cramer_matrix['cramer_v']>0.1]['features'].iloc[0],
annotation_text="variables avec V de Cramer > 0.1",
annotation_position="bottom right",
line_color="#D38F00", line_dash="dash",
line_width=1
)
fig.show()
.... analyse de liaison entre les variables catégorielles
features cramer_v p_value DoF
0 Metro_2013 0.2293 0.0 1
1 Rural_urban_continuum_code_2013 0.2683 0.0 8
2 Urban_influence_code_2013 0.2688 0.0 11
3 State_name 0.3756 0.0 49
4 State_code 0.3756 0.0 49
print("....Présélection de variables via des modules implementés")
print("..........Filtre à partir de la liaison entre la target et les prédicteurs")
print("...............Cas des variables numériques")
# Sélection des x variables numériques les plus liées à la cible
# sur le base du critère d'information mutuelle.
mic_selector = SelectKBest(score_func=mutual_info_classif, k='all')
mic_selector.fit(X_train[num_cols], y_train)
print("Nombre de variables analysées: ",mic_selector.n_features_in_)
df_SKB_stat = pd.DataFrame({'Feature_name': mic_selector.feature_names_in_, 'Scores': mic_selector.scores_ },).sort_values(by='Scores', ascending = False)
display(df_SKB_stat)
# Liste des variables retenues
mic_features = np.array(num_cols)[mic_selector.get_support()].tolist()
....Présélection de variables via des modules implementés ..........Filtre à partir de la liaison entre la target et les prédicteurs ...............Cas des variables numériques Nombre de variables analysées: 13
| Feature_name | Scores | |
|---|---|---|
| 3 | Percent of adults with a bachelor's degree or ... | 0.310759 |
| 1 | Percent of adults with a high school diploma o... | 0.309016 |
| 4 | POP_ESTIMATE_2019 | 0.283097 |
| 8 | R_INTERNATIONAL_MIG_2019 | 0.262888 |
| 6 | NET_MIG_2019 | 0.252734 |
| 12 | Median_Household_Income_2019 | 0.249164 |
| 5 | N_POP_CHG_2019 | 0.230935 |
| 0 | Percent of adults with less than a high school... | 0.225262 |
| 7 | R_NATURAL_INC_2019 | 0.218058 |
| 2 | Percent of adults completing some college or a... | 0.216338 |
| 9 | R_DOMESTIC_MIG_2019 | 0.204963 |
| 10 | PCTPOVALL_2019 | 0.099384 |
| 11 | Unemployment_rate_2019 | 0.023417 |
cat_cols_update = []
for col in cat_cols:
if col not in {'FIPS_code','Area_name'}:
cat_cols_update.append(col)
print(cat_cols_update)
all_cols_update = []
for col in all_cols:
if col not in {'FIPS_code','Area_name'}:
all_cols_update.append(col)
print("....Encodage des variables catégorielles en one hot encoding")
# Encodage des variables catégorielles en one hot encoding
X_train_dummies = pd.get_dummies(X_train[all_cols_update], columns=cat_cols_update, prefix_sep='___')
print("....Normalisation des variables")
# Normalisation des variables
scaler = RobustScaler()
scaler = scaler.fit_transform(X_train_dummies)
X_train_dummies[X_train_dummies.columns.tolist()] = scaler
print("....Définition du classifieur pour l'entraînement des modèles")
# Définition du classifieur pour l'entraînement des modèles
rf_boruta = RandomForestClassifier(n_jobs=-1, max_depth=3)
print("....Paramètre méthode BORUTA")
# Compléter les paramètres de la méthode boruta
set_seed = 42
boruta_selector = BorutaPy(rf_boruta, n_estimators='auto', verbose=0, random_state=set_seed)
print("....Entrainement BORUTA")
# Entraîner boruta
X_boruta = X_train_dummies.values
y_boruta = y_train.values.ravel()
boruta_selector.fit(X_boruta, y_boruta)
['State_name', 'State_code', 'Rural_urban_continuum_code_2013', 'Urban_influence_code_2013', 'Metro_2013'] ....Encodage des variables catégorielles en one hot encoding ....Normalisation des variables ....Définition du classifieur pour l'entraînement des modèles ....Paramètre méthode BORUTA ....Entrainement BORUTA
C:\Users\user\AppData\Local\Temp\ipykernel_7904\2686358787.py:13: FutureWarning: In a future version, the Index constructor will not infer numeric dtypes when passed object-dtype sequences (matching Series behavior)
BorutaPy(estimator=RandomForestClassifier(max_depth=3, n_estimators=329,
n_jobs=-1,
random_state=RandomState(MT19937) at 0x1D61D69AB40),
n_estimators='auto',
random_state=RandomState(MT19937) at 0x1D61D69AB40)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. BorutaPy(estimator=RandomForestClassifier(max_depth=3, n_estimators=329,
n_jobs=-1,
random_state=RandomState(MT19937) at 0x1D61D69AB40),
n_estimators='auto',
random_state=RandomState(MT19937) at 0x1D61D69AB40)RandomForestClassifier(max_depth=3, n_estimators=329, n_jobs=-1,
random_state=RandomState(MT19937) at 0x1D61D69AB40)RandomForestClassifier(max_depth=3, n_estimators=329, n_jobs=-1,
random_state=RandomState(MT19937) at 0x1D61D69AB40)for i in [1,2]:
rank_rel_tentative = np.where((boruta_selector.ranking_ == i))
boruta_features = X_train_dummies.columns[rank_rel_tentative]
boruta_features = get_features_names(boruta_features)
print("Features de niveau : ",i)
print("Nombre de features total : ", len(all_cols_update))
print("Nombre de features à garder : ", len(boruta_features))
display(boruta_features)
Features de niveau : 1 Nombre de features total : 18 Nombre de features à garder : 18
['Median_Household_Income_2019', 'Metro_2013', 'NET_MIG_2019', 'N_POP_CHG_2019', 'PCTPOVALL_2019', 'POP_ESTIMATE_2019', "Percent of adults completing some college or associate's degree, 2015-19", "Percent of adults with a bachelor's degree or higher, 2015-19", 'Percent of adults with a high school diploma only, 2015-19', 'Percent of adults with less than a high school diploma, 2015-19', 'R_DOMESTIC_MIG_2019', 'R_INTERNATIONAL_MIG_2019', 'R_NATURAL_INC_2019', 'Rural_urban_continuum_code_2013', 'State_code', 'State_name', 'Unemployment_rate_2019', 'Urban_influence_code_2013']
Features de niveau : 2 Nombre de features total : 18 Nombre de features à garder : 2
['State_code', 'State_name']
all_cols_model= []
for col in all_cols_update:
if col not in {'State_name','State_code'}:
all_cols_model.append(col)
cat_cols_model = []
for col in cat_cols_update:
if col not in {'State_name','State_code'}:
cat_cols_model.append(col)
print("....Variables sélectionnées pour modèle : \n")
display(all_cols_model)
X_train = X_train[all_cols_model]
X_test= X_test[all_cols_model]
X_init.to_csv('./targeting_data.csv', index = True, header=True)# avant l'oversampling minority
y_init.to_csv('./target_sample.csv', index = True, header=True) # avant l'oversampling minority
print("\n.... Export X et y initiaux pour outils targeting : OK")
....Variables sélectionnées pour modèle :
['Rural_urban_continuum_code_2013', 'Urban_influence_code_2013', 'Percent of adults with less than a high school diploma, 2015-19', 'Percent of adults with a high school diploma only, 2015-19', "Percent of adults completing some college or associate's degree, 2015-19", "Percent of adults with a bachelor's degree or higher, 2015-19", 'POP_ESTIMATE_2019', 'N_POP_CHG_2019', 'NET_MIG_2019', 'R_NATURAL_INC_2019', 'R_INTERNATIONAL_MIG_2019', 'R_DOMESTIC_MIG_2019', 'PCTPOVALL_2019', 'Metro_2013', 'Unemployment_rate_2019', 'Median_Household_Income_2019']
.... Export X et y initiaux pour outils targeting : OK
# Sélection de modèle
set_seed = 42
models = {
"LogisticRegression":
LogisticRegression(
max_iter=1000,
random_state=set_seed
),
"BaggingClassifier":
BaggingClassifier(
n_estimators=30,
random_state=set_seed
),
"RandomForestClassifier":
RandomForestClassifier(
n_estimators=400,
max_depth=3,
random_state=set_seed
),
"XGBClassifier":
XGBClassifier(
n_estimators=80,
eval_metric='logloss',
random_state=set_seed
)
}
# Boucler sur chacun des modèles
print("---------------------------------------- EVALUATION DES MODELES TESTES --------------------------- ")
for key, value in models.items():
print("\n---------------------------------------- ", key," --------------------------------------------------")
display_model_evaluation(X_train, y_train, X_test, y_test, value, key, 0, "")
---------------------------------------- EVALUATION DES MODELES TESTES ---------------------------
---------------------------------------- LogisticRegression --------------------------------------------------
------------------------------------------------------- PHASE DE MODELISATION SIMPLE ---------------------------------------------------
------------- Métrique d'évaluation AUC -------------
Score AUC sur TRAIN : 0.9324
Score AUC sur TEST : 0.9112
------------- Matrice de confusion -------------
Matrice de Confusion sur y TRAIN:
Prédiction positive Prédiction négative
Réelle Positif 1036 244
Réelle négatif 164 1130
Matrice de Confusion sur y TEST:
Prédiction positive Prédiction négative
Réelle Positif 1016 278
Réelle négatif 191 1089
------------- Métrique d'évaluation F1 SCORE -------------
F1 Score sur y TRAIN : [0.83548387 0.84707646]
F1 Score sur y TEST : [0.81247501 0.82281828]
------------- Classification Report : F1 SCORE -------------
Classification report sur TRAIN :
precision recall f1-score support
0 0.86 0.81 0.84 1280
1 0.82 0.87 0.85 1294
accuracy 0.84 2574
macro avg 0.84 0.84 0.84 2574
weighted avg 0.84 0.84 0.84 2574
Classification report sur TEST :
precision recall f1-score support
0 0.84 0.79 0.81 1294
1 0.80 0.85 0.82 1280
accuracy 0.82 2574
macro avg 0.82 0.82 0.82 2574
weighted avg 0.82 0.82 0.82 2574
------------- Score de Spiegelhalter -------------
Score sur TEST :
3.69339807772129
--------------------Courbe de Lift ------------------
<Figure size 800x800 with 0 Axes>
--------------------Courbe Precision / Recall------------------
--------------------Courbe de calibrage------------------
---------------------------------------- BaggingClassifier --------------------------------------------------
------------------------------------------------------- PHASE DE MODELISATION SIMPLE ---------------------------------------------------
------------- Métrique d'évaluation AUC -------------
Score AUC sur TRAIN : 1.0
Score AUC sur TEST : 0.9878
------------- Matrice de confusion -------------
Matrice de Confusion sur y TRAIN:
Prédiction positive Prédiction négative
Réelle Positif 1279 1
Réelle négatif 0 1294
Matrice de Confusion sur y TEST:
Prédiction positive Prédiction négative
Réelle Positif 1262 32
Réelle négatif 139 1141
------------- Métrique d'évaluation F1 SCORE -------------
F1 Score sur y TRAIN : [0.99960922 0.99961375]
F1 Score sur y TEST : [0.93654917 0.93028944]
------------- Classification Report : F1 SCORE -------------
Classification report sur TRAIN :
precision recall f1-score support
0 1.00 1.00 1.00 1280
1 1.00 1.00 1.00 1294
accuracy 1.00 2574
macro avg 1.00 1.00 1.00 2574
weighted avg 1.00 1.00 1.00 2574
Classification report sur TEST :
precision recall f1-score support
0 0.90 0.98 0.94 1294
1 0.97 0.89 0.93 1280
accuracy 0.93 2574
macro avg 0.94 0.93 0.93 2574
weighted avg 0.94 0.93 0.93 2574
------------- Score de Spiegelhalter -------------
Score sur TEST :
6.482312074220338
--------------------Courbe de Lift ------------------
<Figure size 800x800 with 0 Axes>
--------------------Courbe Precision / Recall------------------
--------------------Courbe de calibrage------------------
---------------------------------------- RandomForestClassifier --------------------------------------------------
------------------------------------------------------- PHASE DE MODELISATION SIMPLE ---------------------------------------------------
------------- Métrique d'évaluation AUC -------------
Score AUC sur TRAIN : 0.923
Score AUC sur TEST : 0.9043
------------- Matrice de confusion -------------
Matrice de Confusion sur y TRAIN:
Prédiction positive Prédiction négative
Réelle Positif 996 284
Réelle négatif 129 1165
Matrice de Confusion sur y TEST:
Prédiction positive Prédiction négative
Réelle Positif 988 306
Réelle négatif 165 1115
------------- Métrique d'évaluation F1 SCORE -------------
F1 Score sur y TRAIN : [0.82827443 0.84943493]
F1 Score sur y TEST : [0.80751941 0.82562014]
------------- Classification Report : F1 SCORE -------------
Classification report sur TRAIN :
precision recall f1-score support
0 0.89 0.78 0.83 1280
1 0.80 0.90 0.85 1294
accuracy 0.84 2574
macro avg 0.84 0.84 0.84 2574
weighted avg 0.84 0.84 0.84 2574
Classification report sur TEST :
precision recall f1-score support
0 0.86 0.76 0.81 1294
1 0.78 0.87 0.83 1280
accuracy 0.82 2574
macro avg 0.82 0.82 0.82 2574
weighted avg 0.82 0.82 0.82 2574
------------- Score de Spiegelhalter -------------
Score sur TEST :
14.562734417743107
--------------------Courbe de Lift ------------------
<Figure size 800x800 with 0 Axes>
--------------------Courbe Precision / Recall------------------
--------------------Courbe de calibrage------------------
---------------------------------------- XGBClassifier --------------------------------------------------
------------------------------------------------------- PHASE DE MODELISATION SIMPLE ---------------------------------------------------
------------- Métrique d'évaluation AUC -------------
Score AUC sur TRAIN : 1.0
Score AUC sur TEST : 0.9825
------------- Matrice de confusion -------------
Matrice de Confusion sur y TRAIN:
Prédiction positive Prédiction négative
Réelle Positif 1280 0
Réelle négatif 0 1294
Matrice de Confusion sur y TEST:
Prédiction positive Prédiction négative
Réelle Positif 1266 28
Réelle négatif 127 1153
------------- Métrique d'évaluation F1 SCORE -------------
F1 Score sur y TRAIN : [1. 1.]
F1 Score sur y TEST : [0.94231485 0.93701747]
------------- Classification Report : F1 SCORE -------------
Classification report sur TRAIN :
precision recall f1-score support
0 1.00 1.00 1.00 1280
1 1.00 1.00 1.00 1294
accuracy 1.00 2574
macro avg 1.00 1.00 1.00 2574
weighted avg 1.00 1.00 1.00 2574
Classification report sur TEST :
precision recall f1-score support
0 0.91 0.98 0.94 1294
1 0.98 0.90 0.94 1280
accuracy 0.94 2574
macro avg 0.94 0.94 0.94 2574
weighted avg 0.94 0.94 0.94 2574
------------- Score de Spiegelhalter -------------
Score sur TEST :
4.657148251166241
--------------------Courbe de Lift ------------------
<Figure size 800x800 with 0 Axes>
--------------------Courbe Precision / Recall------------------
--------------------Courbe de calibrage------------------
print(".... Définitions des hyperparamètres ")
# Définitions des hyperparamètres
set_seed = 42
params_grid_log = {'C': [0.1, 0.3, 0.8, 1],
'max_iter': [1000, 1500, 2000],
'class_weight' : ['balanced']
}
params_grid_bag = {'n_estimators': [30,50,80]
}
params_grid_xgb = {'gamma': [0, 0.1, 0.3],
'learning_rate': [0.01, 0.1, 0.3],
'max_depth': [3, 5, 6],
'n_estimators': [100, 120,140],
'reg_alpha': [0, 0.1, 0.4, 1],
'reg_lambda': [0, 0.1, 0.4, 1]
}
print(".... Instanciation du classifieur ")
# Instanciation du classifieur
log_estimator = LogisticRegression(
random_state=set_seed
)
bag_estimator = BaggingClassifier(
random_state=set_seed
)
xgb_estimator = XGBClassifier(
eval_metric='logloss',
random_state=set_seed
)
print(".... Recherche du meilleure hyperparamètre ")
# Recherche du meilleure hyperparamètre
cv_grid_search_log = RandomizedSearchCV(
estimator=log_estimator,
param_distributions=params_grid_log,
scoring = 'f1',
random_state=set_seed,
n_iter=12,
n_jobs = -1,
cv=5,
verbose=2
)
cv_grid_search_bag = RandomizedSearchCV(
estimator=bag_estimator,
param_distributions=params_grid_bag,
scoring = 'f1',
random_state=set_seed,
n_iter=3,
n_jobs = -1,
cv=5,
verbose=2
)
cv_grid_search_xgb = RandomizedSearchCV(
estimator=xgb_estimator,
param_distributions=params_grid_xgb,
scoring = 'f1',
random_state=set_seed,
n_iter=20,
n_jobs = -1,
cv=5,
verbose=2
)
print(".... Calibrage du modèle ")
# Entrainement et évaluation du modèle
print("\n---------------------------------------------------------- Logistic Classifier best Param -----------------------------------------------\n")
display_model_evaluation(X_train, y_train, X_test, y_test, cv_grid_search_log, "logistic_model", 2, LogisticRegression(random_state=set_seed))
print("\n------------------------------------------------------- Bagging Classifier best Param ----------------------------------------------------\n")
display_model_evaluation(X_train, y_train, X_test, y_test, cv_grid_search_bag, "bagging_model", 2, BaggingClassifier(random_state=set_seed))
print("\n------------------------------------------------------- XGB Classifier best Param ---------------------------------------------------------\n")
display_model_evaluation(X_train, y_train, X_test, y_test, cv_grid_search_xgb, "xgb_model", 2, XGBClassifier(random_state=set_seed))
.... Définitions des hyperparamètres
.... Instanciation du classifieur
.... Recherche du meilleure hyperparamètre
.... Calibrage du modèle
---------------------------------------------------------- Logistic Classifier best Param -----------------------------------------------
Fitting 5 folds for each of 12 candidates, totalling 60 fits
------------- Métrique d'évaluation AUC -------------
Score AUC sur TRAIN : 0.9304
Score AUC sur TEST : 0.9112
------------- Matrice de confusion -------------
Matrice de Confusion sur y TRAIN:
Prédiction positive Prédiction négative
Réelle Positif 1024 256
Réelle négatif 149 1145
Matrice de Confusion sur y TEST:
Prédiction positive Prédiction négative
Réelle Positif 1013 281
Réelle négatif 190 1090
------------- Métrique d'évaluation F1 SCORE -------------
F1 Score sur y TRAIN : [0.83489605 0.84972171]
F1 Score sur y TEST : [0.81137365 0.8223312 ]
------------- Classification Report : F1 SCORE -------------
Classification report sur TRAIN :
precision recall f1-score support
0 0.87 0.80 0.83 1280
1 0.82 0.88 0.85 1294
accuracy 0.84 2574
macro avg 0.85 0.84 0.84 2574
weighted avg 0.84 0.84 0.84 2574
Classification report sur TEST :
precision recall f1-score support
0 0.84 0.78 0.81 1294
1 0.80 0.85 0.82 1280
accuracy 0.82 2574
macro avg 0.82 0.82 0.82 2574
weighted avg 0.82 0.82 0.82 2574
------------- Score de Spiegelhalter -------------
Score sur TEST :
0.0012095846929866723
--------------------Courbe de Lift ------------------
<Figure size 800x800 with 0 Axes>
--------------------Courbe Precision / Recall------------------
--------------------Courbe de calibrage------------------
-------------------- Export du modèle au format .sav avec optimisation des hyperparamètres------------------
....Fichier logistic_model_bef_cal.sav exporté
-------------------------------------------- PHASE DE CALIBRAGE FINALE -----------------------------------------------------
---------------------------- PARAMETRES OPTIMAUX UTILISES PAR LE MODELE : --------------------------------
{'max_iter': 1000, 'class_weight': 'balanced', 'C': 0.1}
------------- Métrique d'évaluation AUC -------------
Score AUC sur TRAIN : 0.9301
Score AUC sur TEST : 0.9109
------------- Matrice de confusion -------------
Matrice de Confusion sur y TRAIN:
Prédiction positive Prédiction négative
Réelle Positif 1031 249
Réelle négatif 155 1139
Matrice de Confusion sur y TEST:
Prédiction positive Prédiction négative
Réelle Positif 1024 270
Réelle négatif 191 1089
------------- Métrique d'évaluation F1 SCORE -------------
F1 Score sur y TRAIN : [0.83617194 0.84936614]
F1 Score sur y TEST : [0.81626146 0.82531262]
------------- Classification Report : F1 SCORE -------------
Classification report sur TRAIN :
precision recall f1-score support
0 0.87 0.81 0.84 1280
1 0.82 0.88 0.85 1294
accuracy 0.84 2574
macro avg 0.84 0.84 0.84 2574
weighted avg 0.84 0.84 0.84 2574
Classification report sur TEST :
precision recall f1-score support
0 0.84 0.79 0.82 1294
1 0.80 0.85 0.83 1280
accuracy 0.82 2574
macro avg 0.82 0.82 0.82 2574
weighted avg 0.82 0.82 0.82 2574
------------- Score de Spiegelhalter -------------
Score sur TEST :
1.8527769127968794
--------------------Courbe de Lift ------------------
<Figure size 800x800 with 0 Axes>
--------------------Courbe Precision / Recall------------------
--------------------Courbe de calibrage------------------
-------------------- Export du modèle au format .sav après calibrage------------------
.... Fichier logistic_model_cal.sav exporté
------------------------------------------------------- Bagging Classifier best Param ----------------------------------------------------
Fitting 5 folds for each of 3 candidates, totalling 15 fits
------------- Métrique d'évaluation AUC -------------
Score AUC sur TRAIN : 1.0
Score AUC sur TEST : 0.9882
------------- Matrice de confusion -------------
Matrice de Confusion sur y TRAIN:
Prédiction positive Prédiction négative
Réelle Positif 1279 1
Réelle négatif 0 1294
Matrice de Confusion sur y TEST:
Prédiction positive Prédiction négative
Réelle Positif 1262 32
Réelle négatif 134 1146
------------- Métrique d'évaluation F1 SCORE -------------
F1 Score sur y TRAIN : [0.99960922 0.99961375]
F1 Score sur y TEST : [0.93828996 0.93246542]
------------- Classification Report : F1 SCORE -------------
Classification report sur TRAIN :
precision recall f1-score support
0 1.00 1.00 1.00 1280
1 1.00 1.00 1.00 1294
accuracy 1.00 2574
macro avg 1.00 1.00 1.00 2574
weighted avg 1.00 1.00 1.00 2574
Classification report sur TEST :
precision recall f1-score support
0 0.90 0.98 0.94 1294
1 0.97 0.90 0.93 1280
accuracy 0.94 2574
macro avg 0.94 0.94 0.94 2574
weighted avg 0.94 0.94 0.94 2574
------------- Score de Spiegelhalter -------------
Score sur TEST :
7.095178751290979
--------------------Courbe de Lift ------------------
<Figure size 800x800 with 0 Axes>
--------------------Courbe Precision / Recall------------------
--------------------Courbe de calibrage------------------
-------------------- Export du modèle au format .sav avec optimisation des hyperparamètres------------------
....Fichier bagging_model_bef_cal.sav exporté
-------------------------------------------- PHASE DE CALIBRAGE FINALE -----------------------------------------------------
---------------------------- PARAMETRES OPTIMAUX UTILISES PAR LE MODELE : --------------------------------
{'n_estimators': 50}
------------- Métrique d'évaluation AUC -------------
Score AUC sur TRAIN : 1.0
Score AUC sur TEST : 0.9846
------------- Matrice de confusion -------------
Matrice de Confusion sur y TRAIN:
Prédiction positive Prédiction négative
Réelle Positif 1277 3
Réelle négatif 0 1294
Matrice de Confusion sur y TEST:
Prédiction positive Prédiction négative
Réelle Positif 1249 45
Réelle négatif 99 1181
------------- Métrique d'évaluation F1 SCORE -------------
F1 Score sur y TRAIN : [0.99882675 0.99884215]
F1 Score sur y TEST : [0.94549584 0.94253791]
------------- Classification Report : F1 SCORE -------------
Classification report sur TRAIN :
precision recall f1-score support
0 1.00 1.00 1.00 1280
1 1.00 1.00 1.00 1294
accuracy 1.00 2574
macro avg 1.00 1.00 1.00 2574
weighted avg 1.00 1.00 1.00 2574
Classification report sur TEST :
precision recall f1-score support
0 0.93 0.97 0.95 1294
1 0.96 0.92 0.94 1280
accuracy 0.94 2574
macro avg 0.94 0.94 0.94 2574
weighted avg 0.94 0.94 0.94 2574
------------- Score de Spiegelhalter -------------
Score sur TEST :
4.534615424649292
--------------------Courbe de Lift ------------------
<Figure size 800x800 with 0 Axes>
--------------------Courbe Precision / Recall------------------
--------------------Courbe de calibrage------------------
-------------------- Export du modèle au format .sav après calibrage------------------
.... Fichier bagging_model_cal.sav exporté
------------------------------------------------------- XGB Classifier best Param ---------------------------------------------------------
Fitting 5 folds for each of 20 candidates, totalling 100 fits
------------- Métrique d'évaluation AUC -------------
Score AUC sur TRAIN : 0.9999
Score AUC sur TEST : 0.9785
------------- Matrice de confusion -------------
Matrice de Confusion sur y TRAIN:
Prédiction positive Prédiction négative
Réelle Positif 1272 8
Réelle négatif 0 1294
Matrice de Confusion sur y TEST:
Prédiction positive Prédiction négative
Réelle Positif 1247 47
Réelle négatif 130 1150
------------- Métrique d'évaluation F1 SCORE -------------
F1 Score sur y TRAIN : [0.9968652 0.99691834]
F1 Score sur y TEST : [0.93373268 0.92854259]
------------- Classification Report : F1 SCORE -------------
Classification report sur TRAIN :
precision recall f1-score support
0 1.00 0.99 1.00 1280
1 0.99 1.00 1.00 1294
accuracy 1.00 2574
macro avg 1.00 1.00 1.00 2574
weighted avg 1.00 1.00 1.00 2574
Classification report sur TEST :
precision recall f1-score support
0 0.91 0.96 0.93 1294
1 0.96 0.90 0.93 1280
accuracy 0.93 2574
macro avg 0.93 0.93 0.93 2574
weighted avg 0.93 0.93 0.93 2574
------------- Score de Spiegelhalter -------------
Score sur TEST :
2.2178956980022693
--------------------Courbe de Lift ------------------
<Figure size 800x800 with 0 Axes>
--------------------Courbe Precision / Recall------------------
--------------------Courbe de calibrage------------------
-------------------- Export du modèle au format .sav avec optimisation des hyperparamètres------------------
....Fichier xgb_model_bef_cal.sav exporté
-------------------------------------------- PHASE DE CALIBRAGE FINALE -----------------------------------------------------
---------------------------- PARAMETRES OPTIMAUX UTILISES PAR LE MODELE : --------------------------------
{'reg_lambda': 1, 'reg_alpha': 0.4, 'n_estimators': 120, 'max_depth': 6, 'learning_rate': 0.1, 'gamma': 0.3}
------------- Métrique d'évaluation AUC -------------
Score AUC sur TRAIN : 0.9999
Score AUC sur TEST : 0.9779
------------- Matrice de confusion -------------
Matrice de Confusion sur y TRAIN:
Prédiction positive Prédiction négative
Réelle Positif 1272 8
Réelle négatif 0 1294
Matrice de Confusion sur y TEST:
Prédiction positive Prédiction négative
Réelle Positif 1249 45
Réelle négatif 117 1163
------------- Métrique d'évaluation F1 SCORE -------------
F1 Score sur y TRAIN : [0.9968652 0.99691834]
F1 Score sur y TEST : [0.93909774 0.93488746]
------------- Classification Report : F1 SCORE -------------
Classification report sur TRAIN :
precision recall f1-score support
0 1.00 0.99 1.00 1280
1 0.99 1.00 1.00 1294
accuracy 1.00 2574
macro avg 1.00 1.00 1.00 2574
weighted avg 1.00 1.00 1.00 2574
Classification report sur TEST :
precision recall f1-score support
0 0.91 0.97 0.94 1294
1 0.96 0.91 0.93 1280
accuracy 0.94 2574
macro avg 0.94 0.94 0.94 2574
weighted avg 0.94 0.94 0.94 2574
------------- Score de Spiegelhalter -------------
Score sur TEST :
3.684322873464807
--------------------Courbe de Lift ------------------
<Figure size 800x800 with 0 Axes>
--------------------Courbe Precision / Recall------------------
--------------------Courbe de calibrage------------------
-------------------- Export du modèle au format .sav après calibrage------------------ .... Fichier xgb_model_cal.sav exporté
print("----------------------- Importance des variables -----------------------------------")
# Charger le model xgb_model.sav
filename = "xgb_model_bef_cal.sav"
model_load = pickle.load(open(filename, 'rb'))
# Récupération du meilleur classifieur
best_model = model_load.named_steps.estimator.best_estimator_
# Récupération importance des variables
importance = best_model.feature_importances_
# Récupération liste des variables
one_hot_features = (
model_load
.named_steps
.preprocessor
.named_transformers_['pipeline-2']
.named_steps['onehotencoder']
.get_feature_names_out(cat_cols_model)
).tolist()
features_cols = num_cols + one_hot_features
# Création dataframe contenant l'importance des variables
feature_imp = (
pd.DataFrame(
{"features_cols": features_cols, "importance": 100 * importance}
)
.sort_values(["importance"], ascending=False)
.reset_index(drop=True)
)
# Représentation graphique : bar plot importance variables
fig = px.bar(feature_imp[0:],
y="features_cols", x="importance",
hover_data={'importance':':.2f'}
)
fig.update_layout(
title="Importance des variables : XGBoost",
xaxis_title="Importance",
yaxis_title="variables",
margin=dict(l=0, r=0, t=30, b=50),
width=1000, height=1000
)
fig.show()
----------------------- Importance des variables -----------------------------------
print("----------------------- Dépendance partielle des variables : ICE -----------------------------------")
# Appliquer le preprocessing des données sur la matrice X_test
X_test_prepro = model_load.named_steps.preprocessor.transform(X_test)
# Transformer la sortie préprocessée en dataframe
# en indiquant bien le nom des colonnes
X_test_prepro = pd.DataFrame(
data=X_test_prepro,
columns=features_cols
)
list_n = list(range(0,len(features_cols)))
for i in list_n:
# Graphique de dépendance partielle pour la variable
PartialDependenceDisplay.from_estimator(
estimator=best_model,
X=X_test_prepro,
feature_names=np.array(features_cols),
features=[i],
kind='individual',
response_method="predict_proba"
)
----------------------- Dépendance partielle des variables : ICE -----------------------------------
C:\Users\user\.conda\envs\SDA_P4\lib\site-packages\sklearn\inspection\_plot\partial_dependence.py:1448: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`). Consider using `matplotlib.pyplot.close()`.
# Expliquer la prédiction avec LIME
set_seed = 42
lime_explainer = lime_tabular.LimeTabularExplainer(
training_data=X_test_prepro.to_numpy(),
feature_names=features_cols,
class_names=best_model.classes_,
verbose=True,
mode='classification',
random_state=set_seed
)
i = 30
exp = lime_explainer.explain_instance(
data_row=X_test_prepro.to_numpy()[i],
predict_fn=best_model.predict_proba,
num_features=5
)
exp.show_in_notebook(show_table=True)
Intercept 0.46211653509262524 Prediction_local [0.70687681] Right: 0.40144438
# Charger le model xgb_model.sav
filename_log = "logistic_model_bef_cal.sav"
model_load_log = pickle.load(open(filename_log, 'rb'))
# Récupération du meilleur classifieur
best_model = model_load_log.named_steps.estimator.best_estimator_
print(best_model)
log_coef = str(best_model.coef_)
#print(log_coef)
log_coef_cor = log_coef.replace('[[',"")
log_coef_cor = log_coef_cor.replace(']]',"")
log_coef_cor = log_coef_cor.replace('\n',"")
log_coef_cor = log_coef_cor.replace(' ',' ')
log_coef_cor = log_coef_cor.replace(' ',' ')
log_coef_cor = log_coef_cor.replace(' ',' ')
log_coef_list = log_coef_cor.split()
log_coef_list_int = [float(s) for s in log_coef_list]
#print(log_coef_list_int)
# Récupération liste des variables
one_hot_features = (
model_load_log
.named_steps
.preprocessor
.named_transformers_['pipeline-2']
.named_steps['onehotencoder']
.get_feature_names_out(cat_cols_model)
).tolist()
features_cols = num_cols + one_hot_features
# Création dataframe contenant l'importance des variables
feature_imp = (
pd.DataFrame(
{"features_cols": features_cols, "log_coef": log_coef_list_int}
)
.sort_values(["log_coef"], ascending=False)
.reset_index(drop=True)
)
# Représentation graphique : bar plot importance variables
fig = px.bar(feature_imp[0:],
y="features_cols", x="log_coef",
hover_data={'log_coef':':.2f'}
)
fig.update_layout(
title="Importance des variables : Logistic Reg",
xaxis_title="log_coef",
yaxis_title="variables",
margin=dict(l=0, r=0, t=30, b=50),
width=1000, height=1000
)
fig.show()
LogisticRegression(C=0.1, class_weight='balanced', max_iter=1000,
random_state=42)
print("----------------------- Dépendance partielle des variables : ICE -----------------------------------")
# Appliquer le preprocessing des données sur la matrice X_test
X_test_prepro = model_load_log.named_steps.preprocessor.transform(X_test)
# Transformer la sortie préprocessée en dataframe
# en indiquant bien le nom des colonnes
X_test_prepro = pd.DataFrame(
data=X_test_prepro,
columns=features_cols
)
list_n = list(range(0,len(features_cols)))
for i in list_n:
# Graphique de dépendance partielle pour la variable
PartialDependenceDisplay.from_estimator(
estimator=best_model,
X=X_test_prepro.values,
feature_names=np.array(features_cols),
features=[i],
kind='individual',
response_method="predict_proba"
)
----------------------- Dépendance partielle des variables : ICE -----------------------------------
C:\Users\user\.conda\envs\SDA_P4\lib\site-packages\sklearn\inspection\_plot\partial_dependence.py:1448: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`). Consider using `matplotlib.pyplot.close()`.
# Expliquer la prédiction avec LIME
set_seed = 42
lime_explainer = lime_tabular.LimeTabularExplainer(
training_data=X_test_prepro.to_numpy(),
feature_names=features_cols,
class_names=best_model.classes_,
verbose=True,
mode='classification',
random_state=set_seed
)
i = 30
exp = lime_explainer.explain_instance(
data_row=X_test_prepro.to_numpy()[i],
predict_fn=best_model.predict_proba,
num_features=5
)
exp.show_in_notebook(show_table=True)
Intercept 0.3869617131651754 Prediction_local [0.34521976] Right: 0.6494112697353314
print("----------------------- Importance des variables -----------------------------------")
# Charger le model xgb_model.sav
filename_bag = "bagging_model_bef_cal.sav"
model_load_bag = pickle.load(open(filename_bag, 'rb'))
# Récupération du meilleur classifieur
best_model = model_load_bag.named_steps.estimator.best_estimator_
# Récupération importance des variables
importance = np.mean([
tree.feature_importances_ for tree in best_model.estimators_
], axis=0)
# Récupération liste des variables
one_hot_features = (
model_load_bag
.named_steps
.preprocessor
.named_transformers_['pipeline-2']
.named_steps['onehotencoder']
.get_feature_names_out(cat_cols_model)
).tolist()
features_cols = num_cols + one_hot_features
# Création dataframe contenant l'importance des variables
feature_imp = (
pd.DataFrame(
{"features_cols": features_cols, "importance": 100 * importance}
)
.sort_values(["importance"], ascending=False)
.reset_index(drop=True)
)
# Représentation graphique : bar plot importance variables
fig = px.bar(feature_imp[0:],
y="features_cols", x="importance",
hover_data={'importance':':.2f'}
)
fig.update_layout(
title="Importance des variables : Bagging",
xaxis_title="Importance",
yaxis_title="variables",
margin=dict(l=0, r=0, t=30, b=50),
width=1000, height=1000
)
fig.show()
----------------------- Importance des variables -----------------------------------
print("----------------------- Dépendance partielle des variables : ICE -----------------------------------")
# Appliquer le preprocessing des données sur la matrice X_test
X_test_prepro = model_load_bag.named_steps.preprocessor.transform(X_test)
# Transformer la sortie préprocessée en dataframe
# en indiquant bien le nom des colonnes
X_test_prepro = pd.DataFrame(
data=X_test_prepro,
columns=features_cols
)
list_n = list(range(0,len(features_cols)))
for i in list_n:
# Graphique de dépendance partielle pour la variable
PartialDependenceDisplay.from_estimator(
estimator=best_model,
X=X_test_prepro.values,
feature_names=np.array(features_cols),
features=[i],
kind='individual',
response_method="predict_proba"
)
----------------------- Dépendance partielle des variables : ICE -----------------------------------
C:\Users\user\.conda\envs\SDA_P4\lib\site-packages\sklearn\inspection\_plot\partial_dependence.py:1448: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`). Consider using `matplotlib.pyplot.close()`.
# Expliquer la prédiction avec LIME
set_seed = 42
lime_explainer = lime_tabular.LimeTabularExplainer(
training_data=X_test_prepro.to_numpy(),
feature_names=features_cols,
class_names=best_model.classes_,
verbose=True,
mode='classification',
random_state=set_seed
)
i = 30
exp = lime_explainer.explain_instance(
data_row=X_test_prepro.to_numpy()[i],
predict_fn=best_model.predict_proba,
num_features=5
)
exp.show_in_notebook(show_table=True)
Intercept 0.5823873786206264 Prediction_local [0.6461511] Right: 0.42